home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / hce.lha / HCE / Examples / CLIB / CCheck / CCheck.c next >
Encoding:
C/C++ Source or Header  |  1992-09-02  |  22.5 KB  |  900 lines

  1. /*
  2.  * CCHECK.C -- Amiga Lattice C version 4/8/86
  3.  *
  4.  *
  5.  * Copyright: The Regents of the University of California
  6.  *   [Note - since Steve Draper distributed cchk.c over
  7.  *    Usenet, I assume it's effectively in the public
  8.  *    domain. JCM
  9.  *
  10.  * Title:  ccheck
  11.  *
  12.  * Purpose: To find and report all badly matched openers and
  13.  *   closers plus assignment/equality confusions
  14.  *   in a c source file.
  15.  *
  16.  *
  17.  * Author:  Steve Draper, expanding cnest by Tom Anderson
  18.  *
  19.  * Usage:  ccheck [-q] [-v] <filename1> <filename2> ...
  20.  *
  21.  * History (in reverse order to minimize reading time for updates):
  22.  *
  23.  *   June 13, 1994 Jason Petty
  24.  *   - Must get valid file name else exits with usage.
  25.  *     Changes marked VANSOFT.
  26.  *
  27.  *
  28.  *   April 8, 1986  Converted to Amiga Lattice C from from butchered text
  29.  *                  file.  If any one can supply me with the original source
  30.  *                  I would appreciate it.  IF-ELSE check seems flaky.
  31.  *  
  32.  *                           Thom Althoff (BIX althoff)
  33.  *                       c/o American Broadcasting Companies
  34.  *                           30 W. 67th St Video Tape Tech Support 
  35.  *                           Floor B1
  36.  *                           New York City, N.Y. 10023
  37.  *
  38.  *
  39.  *   June 18, 1985  Converted to Aztec C - removed BDS C code  -  Rick Moore
  40.  *
  41.  *   January 9, 1983  Single BDS/UNIX source created
  42.  *      as CCHECK.C  -- Jeff Martin
  43.  *
  44.  *   December 29, 1982 Adapted for BDS C --
  45.  *       Jeff Martin at home.
  46.  *
  47.  *   December 20, 1982 Converted to cchk --
  48.  *       Steve Draper at UCSD
  49.  *
  50.  *   December 9, 1982 Jeffrey Mogul at Stanford
  51.  *    - checks for unclosed comment at end of file.
  52.  *
  53.  *   December 3, 1982 creation date --
  54.  *      Tom Anderson at microsof!fluke
  55.  *
  56.  */
  57.  
  58. #include <stdio.h>
  59. #include <ctype.h>
  60.  
  61. #define TRUE 1
  62. #define FALSE 0
  63. #define SPACE 32
  64.  
  65. #define BRACE 1
  66. #define SQBRAK  2
  67. #define PAREN 3
  68. #define IF 4
  69. #define IFCOND 5
  70. #define WHLCOND 6
  71. #define THEN 7
  72. #define ELSE 8
  73.  
  74. #define STACKSIZ 64
  75.  
  76. struct brak
  77. {
  78.     int type, b_indent, b_ln;
  79. } stack[STACKSIZ];
  80.  
  81. #define rmbrak(N) (top -= N, stackc -= N)
  82. #define myungetc(C)  ungetc(((C) == '\n' ? SPACE : (C)), infile)
  83.  
  84. #define VFLAG "-v"
  85. #define QFLAG "-q"
  86. #define SFLAG "-s"
  87.  
  88. int firsttime; /* This was a static in mygetchar() */
  89.  
  90. int mygetchar(), pr();
  91. void checkelse(), newbrak(), checkcloser(), prtype();
  92. void usage();
  93.  
  94. FILE *infile;
  95. int ln, indent, commindent, stackc, commln;
  96. int singlequoterr, oddsinglequote, bracecnt, parencnt, sqbrakcnt;
  97. int errstatus, wstatus;
  98. int errnmb, wnmb;
  99. int verbose;
  100. char *filename;
  101. struct brak *top;
  102.  
  103. void usage(op) /* Added, VANSOFT. */
  104. int op;
  105. {
  106.   printf(
  107.   "\n\n\nCCHECK: Copyright - The Regents of the University of California.\n");
  108.   printf("Author: Steve Draper.\n\n");
  109.   printf("Purpose: To find and report all badly matched openers and\n");
  110.   printf(
  111.   "closers plus assignment/equality confusions in a c source file.\n\n");
  112.  
  113.   printf("USAGE:  CCHECK [-q] [-v] <filename1> <filename2> ...\n\n");
  114.   printf("Flags:\n");
  115.   printf("\t-q   -  Suppress warning messages.\n");
  116.   printf("\t-v   -  Verbose.\n\n\n");
  117.  
  118.  if(!op)
  119.   exit(10); /* Exit error. */
  120. }
  121.  
  122. main(argc, argv)
  123. unsigned argc ;
  124. char *argv[] ;
  125. {
  126.     register int c;
  127.     int i;
  128.     int doubleqflag;
  129.     unsigned file_index;
  130.  
  131.     wnmb = 0;
  132.     verbose = 0;
  133.     file_index = 1;
  134.  
  135.     while (argc > 1  &&  argv[file_index][0] == '-')
  136.        {
  137.         if (strcmp(argv[file_index], VFLAG) == 0)
  138.             verbose++;
  139.         if (strcmp(argv[file_index], QFLAG) == 0)
  140.             wnmb = -2;
  141.         if (strcmp(argv[file_index], SFLAG) == 0)
  142.             wnmb = -2;
  143.         file_index++;
  144.         argc--;
  145.        }
  146.  
  147.     do
  148.      {
  149.         /* INIT for each file */
  150.         firsttime = 1;
  151.         doubleqflag = 0;
  152.         errstatus = wstatus = 0;
  153.         ln = 1;
  154.         indent = 0;
  155.         commindent = 0;
  156.         singlequoterr = oddsinglequote = parencnt = sqbrakcnt = bracecnt = 0;
  157.         errnmb = 0;
  158.         if (wnmb > -2)
  159.             wnmb = 0;
  160.         newbrak(0);
  161.  
  162.         if (argc == 1 || argc == 0)
  163.           {
  164.             usage(NULL); /* usage. Added, VANSOFT. */
  165.            }
  166.         else
  167.          {
  168.           if ((infile = fopen(argv[file_index], "r")) == (FILE * ) NULL)
  169.            {
  170.             usage(1); /* 1 = don't 'exit()' yet. (usage. Added,VANSOFT) */
  171.      fprintf(stdout, "%s: Can't access %s!\n\n",argv[0],argv[file_index]);
  172.             exit(10); /* exit error. */ 
  173.             }
  174.            filename = argv[file_index]; 
  175.           }
  176.  
  177.         while ( ( c = mygetchar()) !=  EOF )
  178.            {
  179.             if (verbose == 2)
  180.                {
  181.                 for (i = stackc; i > 0; i--)
  182.                   {
  183.             printf("%c %d: type ", c, i);
  184.             prtype(stack[i].type);
  185.             printf(", indent %d, line %d.\n",stack[i].b_indent,stack[i].b_ln);
  186.                   }
  187.                }
  188.  
  189.             switch (c)
  190.             {
  191.             case ';':
  192.                 ungetc(SPACE, infile);
  193.                 while (top->type == ELSE)
  194.                     rmbrak(1);
  195.                 if (top->type == THEN)
  196.                 {
  197.                     rmbrak(1);
  198.                     checkelse();
  199.                 }
  200.                 break;
  201.  
  202.             case '!':
  203.             case '>':
  204.             case '<':
  205.                 /* swallow legit. '=' chars */
  206.                 c = mygetchar();
  207.                 if (c != '=')
  208.                     myungetc(c);
  209.                 break;
  210.  
  211.             case '=':
  212.                 if ((top - 1)->type == IFCOND  ||  (top - 1)->type == WHLCOND)
  213.                    {
  214.                     c = mygetchar();
  215.                     if (c != '=')
  216.                       {
  217.                         myungetc(c);
  218.               if(pr(1))
  219.                printf("Assignment instead of equals in conditional,%d\n", ln);
  220.                     }
  221.                 }
  222.                 break;
  223.  
  224.             case '\n':
  225.             case SPACE:
  226.                 c = mygetchar();
  227.                 switch (c) {
  228.                 case 'i':
  229.                     /* if */
  230.                     c = mygetchar();
  231.                   if (c == 'f' && !isalpha(c = fgetc(infile)) && !isdigit(c))
  232.                       {
  233.                         ungetc(c, infile);
  234.                         newbrak(IF);
  235.                         while ((c = mygetchar()) == SPACE ||  c == '\n');
  236.                         if (c != '(')
  237.                         {
  238.                             if (pr(1))
  239.                                 printf("Bad if (no condition) line %d.\n",ln);
  240.                             rmbrak(1);
  241.                         }
  242.                         else
  243.                             newbrak(IFCOND);
  244.                             myungetc(c);
  245.                     }
  246.                         else
  247.                         myungetc(c);
  248.                     break;
  249.                 case 'w':
  250.                     /* while */
  251.                     if ((c = mygetchar()) == 'h'
  252.                       &&  (c = mygetchar()) == 'i'
  253.                       &&  (c = mygetchar()) == 'l'
  254.                       &&  (c = mygetchar()) == 'e'
  255.                       &&  !isalpha(c = fgetc(infile))  &&  !isdigit(c))
  256.                       {
  257.                         ungetc(c, infile);
  258.                         while ((c = mygetchar()) == SPACE ||  c == '\n');
  259.                         if (c != '(')
  260.                          {
  261.                         if(pr(1))
  262.                            printf("Bad while (no condition) line %d.\n",ln);
  263.                         }
  264.                         else
  265.                             newbrak(WHLCOND);
  266.                             myungetc(c);
  267.                     }
  268.                     else
  269.                         myungetc(c);
  270.                     break;
  271.                 case 'e':
  272.                     /* else */
  273.                     myungetc(c);
  274.                     checkelse();
  275.                     break;
  276.  
  277.                 default:
  278.                     myungetc(c);
  279.                     break;
  280.                 }
  281.                 break;
  282.  
  283.             case '*':
  284.                 /* close comment ? */
  285.                 c = mygetchar();
  286.                 if (c != '/')
  287.                 {
  288.                     myungetc(c);
  289.                     break;
  290.                 }
  291.  
  292.    if(pr(1))
  293.       printf("Line %d: Comment close without open, indent %d\n",ln, indent);
  294.  
  295.                 break;
  296.  
  297.             case '\'':
  298.              if((c = fgetc(infile)) != '\\')
  299.                 {
  300.                     if (c == '\''  ||  (c = fgetc(infile)) != '\'')
  301.                     {
  302.                         if (pr(1))
  303.                             printf("Bad character constant line %d\n", ln);
  304.                         singlequoterr = 1;
  305.                      }
  306.                 }
  307.                else 
  308.                 {
  309.                    if(!isdigit(c = fgetc(infile)))
  310.                     {
  311.                      if((c = fgetc(infile)) != '\'')
  312.                         {
  313.                      if(pr(1))
  314.                         printf("Bad character constant with \\ line %d\n",ln);
  315.                         }
  316.                      } 
  317.                    else
  318.                      {
  319.                     if(isdigit(c = fgetc(infile)))
  320.                         if(isdigit(c = fgetc(infile)))
  321.                            c = fgetc(infile);
  322.                     if(c != '\'')
  323.                         if(pr(1))
  324.                        printf("Bad character constant with \\0 line %d\n",ln);
  325.                       }
  326.                  }
  327.                 if(c != '\'')
  328.                   {
  329.                     ungetc(c, infile);
  330.                     oddsinglequote = !oddsinglequote;
  331.                     singlequoterr = 1;
  332.                    }
  333.                 break;
  334.  
  335.             case '"':
  336.                 do
  337.                 {
  338.                     c = fgetc(infile);
  339.                     if (c == EOF)
  340.                     {
  341.               if(pr(2))
  342.                 printf("Error: '\"' quoted string not ended on line %d\n",ln);
  343.                             break;
  344.                     }
  345.                     else
  346.              if (c == '\n')
  347.                 {
  348.               if(doubleqflag == 0)
  349.                 if(pr(0))
  350.                 printf("Warning: '\"' quoted string not ended on line %d",ln);
  351.                         doubleqflag = 1;
  352.                         ln++;
  353.                 }
  354.                else
  355.                     if (c == '\\')
  356.                       {
  357.                         c = SPACE;
  358.                         fgetc(infile);
  359.                       }
  360.                 }
  361.                 while (c != '"');
  362.                 doubleqflag = 0;
  363.                 break;
  364.  
  365.             case '{':
  366.                 if (stackc  &&  indent < top->b_indent)
  367.                     if (pr(0))
  368.                         printf("Indent jumps backwards line %d.\n", ln);
  369.                 newbrak(BRACE);
  370.                 break;
  371.  
  372.             case '}':
  373.                 checkcloser(BRACE);
  374.                 while (top->type == ELSE)
  375.                     rmbrak(1);
  376.                 if (top->type == THEN)
  377.                 {
  378.                     rmbrak(1);
  379.                     checkelse();
  380.                 }
  381.                 break;
  382.  
  383.             case '(':
  384.                 if (stackc  &&  indent < top->b_indent)
  385.                     if (pr(0))
  386.                         printf("Indent jumps backwards line %d.\n", ln);
  387.                 newbrak(PAREN);
  388.                 break;
  389.  
  390.             case ')':
  391.                 checkcloser(PAREN);
  392.                 if (top->type == IFCOND)
  393.                 {
  394.                     rmbrak(1);
  395.                     newbrak(THEN);
  396.                 }
  397.                 else
  398.                 if (top->type == WHLCOND)
  399.                     rmbrak(1);
  400.                 break;
  401.  
  402.             case '[':
  403.                 if (stackc  &&   indent < top->b_indent)
  404.                     if (pr(0))
  405.                         printf("Indent jumps backwards line %d.\n", ln);
  406.                 newbrak(SQBRAK);
  407.                 break;
  408.  
  409.             case ']':
  410.                 checkcloser(SQBRAK);
  411.                 break;
  412.  
  413.             default:
  414.                 break;
  415.  
  416.             }
  417.         }
  418.  
  419.         fclose(infile);
  420.  
  421.         while (stackc > 0)
  422.         {
  423.             pr(2);
  424.             fputs("Unclosed brak at EOF: ", stdout);
  425.             prtype(top->type);
  426.             printf(" opened on line %d.\n", top->b_ln);
  427.             switch (top->type)
  428.             {
  429.             case BRACE:
  430.                 bracecnt++;
  431.                 break;
  432.             case SQBRAK:
  433.                 sqbrakcnt++;
  434.                 break;
  435.             case PAREN:
  436.                 parencnt++;
  437.                 break;
  438.             default:
  439.                 break;
  440.             }
  441.             rmbrak(1);
  442.         }
  443.  
  444.  if((i = (oddsinglequote || bracecnt || sqbrakcnt || parencnt)) || errstatus)
  445.         {
  446.             pr(2);
  447.             printf("Summary:\n");
  448.         }
  449.         else
  450.         {
  451.             if (filename != NULL)
  452.             {
  453.                 fputs(filename, stdout);
  454.                 fputs(": ", stdout);
  455.             }
  456.             printf(" OK\n");
  457.         }
  458.         if (oddsinglequote)
  459.             printf("\tOdd number of single quotes.\n");
  460.         if (bracecnt)
  461.             printf("\t%d too few %s braces.\n", abs(bracecnt), 
  462.                     (bracecnt > 0 ? "closing" : "opening"));
  463.         if (sqbrakcnt)
  464.             printf("\t%d too few %s square brackets.\n", abs(sqbrakcnt),
  465.                    (sqbrakcnt > 0 ? "closing" : "opening"));
  466.         if (parencnt)
  467.             printf("\t%d too few %s parentheses.\n", abs(parencnt), 
  468.                    (parencnt > 0 ? "closing" : "opening"));
  469.         if (errstatus && !i)
  470.             printf("\tPossible error(s), but no net delimiter imbalance.\n");
  471.         putchar('\n');
  472.     }
  473.     while (++file_index < argc);
  474.  
  475.     exit(errstatus ? 2 : wstatus);
  476. }
  477.  
  478. int mygetchar()
  479. {
  480.     register int c;
  481.  
  482.     c = fgetc(infile);
  483.  
  484.     /*
  485.     if (c == ';') {
  486.         ungetc(SPACE, infile);
  487.         return(';');
  488.     }
  489.     */
  490.     if (c == '/') {    /* open comment ? */
  491.         c = fgetc(infile);
  492.         if (c != '*')
  493.         {
  494.             ungetc(c, infile);
  495.             return('/');
  496.         }
  497.         commln = ln;
  498.         commindent = indent;
  499.  
  500.         while (1)
  501.         {
  502.             c = fgetc(infile);
  503.  
  504.             if (c == EOF)
  505.             {   /* last comment never ended */
  506.                 if(pr(2))
  507.                    printf("Comment opened line %d unclosed by end of file.\n",
  508.                             commln);
  509.                 break; /* Get out of this loop! */
  510.             }
  511.             else
  512.             if (c == '/') {  /* nested comment ? */
  513.                 if ((c = fgetc(infile)) == '*')
  514.                 {
  515.               if (pr(0))
  516.                   fprintf(stdout,
  517.       "Nested comment: line %d, indent %d.  First open: line %d indent %d\n", 
  518.                        ln, indent, commln, commindent);
  519.                 }
  520.                 else
  521.                     ungetc(c, infile);
  522.             } else if (c == '*') {  /* end comment ? */
  523.                 if ((c = fgetc(infile)) == '/')
  524.                 {
  525.                     if (indent != commindent  &&  indent - 1 != commindent)
  526.                         if (pr(0))
  527.                             printf(
  528.  "Indent of comment close doesn't match open: lines %d, %d indents %d, %d\n", 
  529.                                    commln, ln, commindent, indent);
  530.  
  531.                     break;    /* only exit from loop, except EOF */
  532.                 }
  533.                 else
  534.                     ungetc(c, infile);
  535.             }
  536.             else
  537.             if (c == '\n')
  538.             {
  539.                 do
  540.                 {                  
  541.                   if (c == SPACE)
  542.                         indent++;
  543.                     else
  544.                     if (c == '\t')                    
  545.                         indent = ((indent + 8) / 8) * 8;
  546.                     else if (c == '\n')
  547.                     {
  548.                         ln++;
  549.                         indent = 0;
  550.                     }
  551.                 }
  552.                 while (isspace(c = fgetc(infile)));
  553.                 ungetc(c, infile);
  554.             }
  555.         }
  556.         return(SPACE);
  557.  
  558.     }
  559.  
  560.     if (c == '\n'  ||  firsttime == 1)
  561.     {
  562.         firsttime = 0;
  563. lf:
  564.         while (1)
  565.         {
  566.             if (c == SPACE)
  567.                 indent++;
  568.             else if (c == '\t')
  569.                 indent = ((indent + 8) / 8) * 8;
  570.             else if (c == '\n')
  571.             {
  572.                 ln++;
  573.                 indent = 0;
  574.                 singlequoterr = 0;
  575.             } else
  576.             {
  577.                 ungetc(c, infile);
  578.                 return('\n');
  579.                 /*NOTREACHED*/
  580.                 break;
  581.             }
  582.             c = fgetc(infile);
  583.         }
  584.     }
  585.  
  586.     if (c == SPACE  ||  c == '\t')
  587.     {
  588.         do
  589.         
  590.             c = fgetc(infile);
  591.         while (c == SPACE  ||  c == '\t');
  592.         if (c != '\n')
  593.         {
  594.             ungetc(c, infile);
  595.             return(SPACE);
  596.         }
  597.         else
  598.             goto lf;
  599.     }
  600.     return(c);
  601. }
  602.  
  603. /*
  604.  * administer count of error msgs. and suppress if too many
  605.  * administer the status var.s
  606.  * prepend file name to msg.
  607.  * flag error msg.s (not warnings) with '*'
  608.  */
  609. int pr(error)
  610. int error;
  611. {
  612.     int i;
  613.  
  614.     if (singlequoterr)
  615.         return(0);
  616.  
  617.     if (verbose)
  618.       {
  619.         for (i = stackc; i > 0; i--)
  620.         {
  621.          printf("%d: type ", i);
  622.          prtype(stack[i].type);
  623.          printf(", indent %d, line %d.\n", stack[i].b_indent, stack[i].b_ln);
  624.          }
  625.       }
  626.  
  627.     if (error == 2)
  628.       {
  629.         errnmb = 0;
  630.         errstatus = 1;
  631.       }
  632.     else
  633.     
  634.     if (error)
  635.        {
  636.         errstatus = 1;
  637.         if (errnmb < 0)
  638.             return(0);
  639.             
  640.         else
  641.         if (errnmb >= 9)
  642.           {
  643.             errnmb = -1;
  644.             printf("Other error messages being suppressed.\n");
  645.             return(0);
  646.           }
  647.         }
  648.     else
  649.     {
  650.         wstatus = 1;
  651.         if (wnmb < 0)
  652.             return(0);
  653.         else if (errnmb + wnmb >= 9)
  654.           {
  655.             wnmb = -1;
  656.             puts("Further warning messages being suppressed.\n");
  657.             return(0);
  658.           }
  659.      }
  660.  
  661.     if (filename != NULL)
  662.       {
  663.         fputs(filename, stdout);
  664.         fputs(": ", stdout);
  665.       }
  666.     if (error)
  667.         putchar('*');
  668.     if (error)
  669.         errnmb++;
  670.     else
  671.         wnmb++;
  672.     return(1);
  673. }
  674.  
  675. void newbrak(newtype)
  676. int newtype;
  677. {
  678.     if (newtype == 0)
  679.       {
  680.         top = stack;
  681.         stackc = 0;
  682.       }
  683.     else
  684.       {
  685.         top++;
  686.         stackc++;
  687.       }
  688.       
  689.     if (stackc >= STACKSIZ)
  690.        {
  691.         if (pr(2))
  692.          {
  693.            printf("***stack overflow, line %d.\n", ln);
  694.          }  
  695.         exit(3);
  696.        }
  697.  
  698.     top->type = newtype;
  699.     top->b_indent = indent;
  700.     top->b_ln = ln;
  701.  
  702. }
  703.  
  704. void prtype(typ)
  705. int typ;
  706. {
  707.     switch (typ)
  708.     {
  709.     case BRACE:
  710.         putchar('}');
  711.         break;
  712.     case PAREN:
  713.         putchar(')');
  714.         break;
  715.     case SQBRAK:
  716.         putchar(']');
  717.         break;
  718.     case IF:
  719.         fputs("if", stdout);
  720.         break;
  721.     case IFCOND:
  722.         fputs("if-condition", stdout);
  723.         break;
  724.     case THEN:
  725.         fputs("then", stdout);
  726.         break;
  727.     case ELSE:
  728.         fputs("else", stdout);
  729.         break;
  730.     case WHLCOND:
  731.         fputs("while-condition", stdout);
  732.         break;
  733.     default:
  734.         fputs("'NULL'", stdout);
  735.         break;
  736.     }
  737. }
  738.  
  739. void checkcloser(typ)
  740. int typ;
  741. {
  742.     int i, found;
  743.  
  744.     i = found = 0;
  745.     if (typ == top->type  &&  top->b_indent == indent)
  746.     {
  747.         rmbrak(1);
  748.         return;
  749.     }
  750.     
  751.     while (!found  &&  ++i < stackc  &&  indent <= (top - i)->b_indent)
  752.         if (typ == (top - i)->type  &&  (top - i)->b_indent == indent)
  753.             found = 1;
  754.  
  755.     if (found)
  756.     {
  757.      if(pr(1))
  758.         printf("Missing closer%s detected line %d:\n", (i > 1 ? "s" :""), ln);
  759.         while (i--)
  760.         {
  761.             if (pr(1))
  762.             {
  763.                 fputs("\tMissing closing ", stdout);
  764.                 prtype(top->type);
  765.                 printf(" opened line %d.\n", top->b_ln);
  766.             }
  767.             switch (top->type)
  768.             {
  769.             case BRACE:
  770.                 bracecnt++;
  771.                 break;
  772.             case SQBRAK:
  773.                 sqbrakcnt++;
  774.                 break;
  775.             case PAREN:
  776.                 parencnt++;
  777.                 break;
  778.             default:
  779.                 break;
  780.             }
  781.             rmbrak(1);
  782.         }
  783.         rmbrak(1); /* the matching brak */
  784.     }
  785.     else
  786.     if (typ == top->type)
  787.     {
  788.         if (indent != top->b_indent)
  789.         {
  790.             if (pr(0)) {
  791.                 fputs("Mismatched indent on closing ", stdout);
  792.                 prtype(typ);
  793.                 printf(" lines %d, %d; indents %d, %d.\n",
  794.                   top->b_ln, ln, top->b_indent, indent);
  795.             }
  796.         }
  797.         rmbrak(1);
  798.     }
  799.       else
  800.       {
  801.         switch (typ)
  802.         {
  803.         case BRACE:
  804.             bracecnt--;
  805.             break;
  806.             case SQBRAK:
  807.             sqbrakcnt--;
  808.             break;
  809.         case PAREN:
  810.             parencnt--;
  811.             break;
  812.         default:
  813.             break;
  814.         }
  815.  
  816.         if (pr(1))
  817.         {
  818.             fputs("Muddle detected at unmatched closing ", stdout);
  819.             prtype(typ);
  820.             printf(" line %d.\n", ln);
  821.         }
  822.     }
  823. }
  824.  
  825. /*
  826.  * removes IF from stack
  827.  * checks else's indent
  828.  */
  829. void checkelse()
  830. {
  831.     int c;
  832.  
  833.     while ((c = mygetchar()) == SPACE  || c == '\n');
  834.     if (c == 'e' &&  (c = mygetchar()) == 'l' &&  (c = mygetchar()) == 's' &&
  835.        (c = mygetchar()) == 'e' &&  !isalpha(c = fgetc(infile)) &&
  836.        !isdigit(c))
  837.       {
  838.         ungetc(c, infile);
  839.         if (top->type == THEN)
  840.             rmbrak(1);
  841.         if (top->type != IF)
  842.         {
  843.             if (pr(1))
  844.                 printf("Else with no if line %d.\n", ln);
  845.         }
  846.           else
  847.           if (indent + 2 < top->b_indent)
  848.           {
  849.             if (pr(1))
  850.                 printf(
  851.     "Dangling else -- bound to wrong if?  \"if\" line %d, \"else\" line %d\n",
  852.                        top->b_ln, ln);
  853.           }
  854.           else
  855.           if (indent != top->b_indent)
  856.           {
  857.             if (pr(0))
  858.             {
  859.                 fputs("Wrong indent for else", stdout);
  860.                 if (indent - 2 >  top->b_indent)
  861.                     fputs(" missing if?", stdout);
  862.             printf(".  \"if\" line %d, \"else\" line %d.\n", top->b_ln,ln);
  863.             }
  864.         }
  865.  
  866.         if (top->type == IF)
  867.             rmbrak(1);
  868.         newbrak(ELSE);
  869.     }
  870.     else
  871.     {
  872.         myungetc(c);
  873.         ungetc(SPACE, infile);  /* BUG?? */
  874.         /* no else so terminate the IF */
  875.         if (top->type == IF)
  876.         {
  877.             rmbrak(1);
  878.             while (top->type == ELSE)
  879.                 rmbrak(1);
  880.             if (top->type == THEN)
  881.             {
  882.                 rmbrak(1);
  883.                 checkelse();
  884.             }
  885.         }
  886.     }
  887. }
  888.  
  889. /*  This function is included because Aztec C does not include an "abs"
  890.     function.  If your library contains this function, this code can be    
  891.     deleted.
  892. */
  893. int abs(i)
  894. {
  895.     int c;
  896.  
  897.     return((i < 0) ? -i : i);
  898. }
  899.  
  900.